<template>
  <div class="page-container">
    <el-form
      ref="dataForm"
      label-width="85px"
      :model="formData"
      :class="!fit ? '' : 'fit-box full-height'"
      :rules="rules"
    >
      <el-row style="margin-top: 10px;">
        <el-col :span="4">
          <el-form-item label="页面名称" prop="name">
            <el-input v-model="formData.name" />
          </el-form-item>
        </el-col>
        <el-col :span="4">
          <el-form-item label="展示类型" prop="type">
            <ac-select
              v-if="!formData.id"
              v-model="formData.type"
              options="普通,标签,可视化"
            />
            <ac-select
              v-if="formData.id && formData.type !== '可视化'"
              v-model="formData.type"
              options="普通,标签"
            />
            <ac-select
              v-if="formData.id && formData.type === '可视化'"
              v-model="formData.type"
              :disabled="true"
              options="可视化"
            />
          </el-form-item>
        </el-col>
        <el-col :span="4" v-if="formData.type === '标签'">
          <el-form-item label="标签位置" prop="tabPosition">
            <ac-select v-model="formData.tabPosition" options="顶部,底部,左侧,右侧" />
          </el-form-item>
        </el-col>
        <el-col :span="4" v-if="formData.type === '标签'">
          <el-form-item label="徽标脚本" prop="tabScriptId">
            <ac-tree
              v-model="formData.tabScriptId"
              data-url="/system/scriptGroovy/queryTree"
              typeSelect="script"
            />
          </el-form-item>
        </el-col>
        <el-col :span="3" v-if="formData.type === '标签'">
          <el-form-item label="切换刷新" prop="tabRefresh">
            <ac-dict-switch v-model="formData.tabRefresh" dictCode="dictYesNo" />
          </el-form-item>
        </el-col>
        <el-col :span="4" v-if="formData.type === '可视化'">
          <el-form-item label="布局模式" prop="layoutMode">
            <ac-select v-model="formData.layoutMode" options="相对,表单,大屏" />
          </el-form-item>
        </el-col>
        <el-col :span="4">
          <el-form-item label="页面目录" prop="folderId">
            <ac-tree
              v-model="formData.folderId"
              data-url="/system/pageFolder/queryTree"
              :leafSelect="false"
            />
          </el-form-item>
        </el-col>
        <el-col :span="4">
          <el-form-item label="样式名称" prop="cssName">
            <el-input v-model="formData.cssName" />
          </el-form-item>
        </el-col>
      </el-row>
      <el-row>
        <el-col :span="24">
          <el-form-item label="页面参数">
            <div
              ref="sortParam"
              :class="['param-box', sortableParamInst ? 'pointer' : '']"
            >
              <div
                class="param-item"
                v-for="param in formData.paramList || []"
                :key="param.id"
              >
                <span>{{param.name}}</span>
                <ac-icon
                  iconId="018dca6db20c6a3aaf68"
                  color="#409EFF"
                  @click.stop="editParam(param)"
                />
                <ac-icon
                  iconId="018dca412c4ebd53fd1d"
                  color="red"
                  @click.prevent="deleteSelectedParam(param)"
                />
              </div>
            </div>
            <el-button
              @click="editParam(null)"
              type="success"
            >添加参数</el-button>
            <el-button
              v-if="!sortableParamInst && (formData.paramList || []).length > 1"
              @click="sortParamList"
              type="primary"
            >开启排序</el-button>
            <el-button
              v-if="sortableParamInst"
              @click="closeParamList"
              type="info"
            >关闭排序</el-button>
          </el-form-item>
        </el-col>
      </el-row>
      <el-row>
        <el-col :span="16"><span class="section-tips">页面组件</span></el-col>
        <el-col :span="8" style="text-align: right;margin-bottom: 8px;">
          <el-button
            v-if="!sortableInst && (formData.compList || []).length > 1"
            type="primary"
            @click="sortPageComp"
          >开启排序</el-button>
          <el-button
            v-if="sortableInst"
            type="info"
            @click="unSortPageComp"
          >关闭排序</el-button>
          <el-button
            v-if="formData.type !== '可视化'"
            type="success"
            @click="addComp"
          >添加组件</el-button>
          <el-button
            v-if="formData.type === '可视化'"
            style="margin-left: 10px;"
            type="primary"
            @click="visualEdit"
          >可视化布局</el-button>
        </el-col>
      </el-row>
      <div :class="!fit ? '' : 'fit-box full-height'">
        <el-table
          ref="sortTable"
          :show-overflow-tooltip="false"
          tooltip-effect="light"
          :class="!fit ? 'field-table' : 'field-table fit-table'"
          width="100%"
          :data="formData.compList"
          :border="true"
          :stripe="false"
          :row-key="getRowKey"
        >
          <el-table-column
            header-align="center"
            label="组件名称"
            :min-width="120"
            prop="name"
          />
          <el-table-column
            header-align="center"
            label="组件类型"
            align="center"
            :width="120"
            prop="type"
          />
          <el-table-column
            header-align="center"
            label="是否显示"
            align="center"
            :width="120"
            prop="showComp"
          >
            <template #default="scope">
              <ac-dict-select
                v-model="scope.row.showComp"
                dictCode="dictYesNo"
                showText
              />
            </template>
          </el-table-column>
          <el-table-column
            header-align="center"
            align="center"
            label="修改时间"
            :width="160"
            prop="updateTime"
          >
            <template #default="scope">
              {{date.formatLongDate(scope.row.updateTime)}}
            </template>
          </el-table-column>
          <el-table-column
            v-if="formData.type !== '可视化'"
            header-align="center"
            align="center"
            label="操作"
            width="160"
          >
            <template #default="scope">
              <el-button
                type="primary"
                @click="editComp(scope.row)"
                link
              >编辑</el-button>
              <el-button
                type="success"
                @click="copyComp(scope.row)"
                link
              >复制</el-button>
              <el-button
                type="danger"
                @click="deleteComp(scope.row)"
                link
              >删除</el-button>
            </template>
          </el-table-column>
        </el-table>
      </div>
    </el-form>
  </div>

  <!--参数编辑-->
  <el-dialog
    v-model="paramVisible"
    width="500px"
    :title="paramTitle"
    :close-on-click-modal="false"
    destroy-on-close
    append-to-body
    draggable
  >
    <el-form
      ref="paramForm"
      label-width="120px"
      label-position="right"
      :model="paramData"
      :rules="paramRules"
    >
      <el-row>
        <el-col :span="24">
          <el-form-item label="参数名" prop="name">
            <el-input v-model="paramData.name" />
          </el-form-item>
        </el-col>
      </el-row>
    </el-form>
    <template #footer>
      <el-button
        size="default"
        type="info"
        @click="paramVisible=false"
      >取消</el-button>
      <el-button
        type="primary"
        size="default"
        @click="submitParamForm"
      >确定</el-button>
    </template>
  </el-dialog>

  <!--页面编辑-->
  <el-dialog
    v-model="compVisible"
    class="no-padding"
    :title="compTitle"
    :close-on-click-modal="false"
    destroy-on-close
    fullscreen
    draggable
    append-to-body
  >
    <PageCompEdit ref="compComp" :options="compData" :pageParamList="formData.paramList" />
    <template #footer>
      <el-button
        size="default"
        type="info"
        @click="compVisible=false"
      >取消</el-button>
      <el-button
        type="primary"
        size="default"
        @click="submitCompForm"
      >确定</el-button>
    </template>
  </el-dialog>

  <!--页面编辑-->
  <el-dialog
    v-model="visualVisible"
    class="no-padding no-header no-scroll"
    :show-header="false"
    :close-on-click-modal="false"
    :close-on-press-escape="false"
    destroy-on-close
    fullscreen
    draggable
  >
    <Component
      :is="visualComp"
      v-bind="visualOptions"
      @save="visualSave"
      @quit="visualVisible = false"
    />
  </el-dialog>
</template>

<script setup>
import { ref, onMounted, watch, nextTick, markRaw } from 'vue';
import api from "@/http/api";
import { ElMessage, ElMessageBox } from "element-plus";
import PageCompEdit from "@/admin/codeless/pageCompEdit.vue";
import VisualEditor from "@/admin/visual/editor.vue";
import DashboardEditor from "@/admin/dashboard/editor.vue";
import tool from "@/utils/tool";
import Sortable from "sortablejs";
import loading from '@/utils/loading';
import date from "@/utils/date";

const emit = defineEmits(['afterSubmit'])
const props = defineProps({
  options: {
    type: Object,
    default: () => {}
  },
  fit: {
    type: Boolean,
    default: true
  }
});

const formData = ref({});
const dataForm = ref();
const rules = ref({
  name: [
    {required: true, message: '请输入名称', trigger: ['change', 'blur']},
    {max: 100, message: '长度必须小于等于 200 个字符！', trigger: ['change', 'blur']}
  ],
  folderId: [
    {required: true, message: '请选择页面目录', trigger: ['change', 'blur']},
  ],
});
const rowFlag = ref(0);
const compTitle = ref('');
const compData = ref();
const compComp = ref();
const compVisible = ref(false);

const visualOptions = ref();
const visualComp = ref();
const visualVisible = ref(false);

const sortableInst = ref();
const sortTable = ref();

const paramVisible = ref(false);
const paramTitle = ref('');
const paramForm = ref();
const paramRules = ref({
  name: [
    {required: true, message: '请输入参数名称', trigger: ['change', 'blur']},
    {max: 100, message: '长度必须小于等于 50 个字符！', trigger: ['change', 'blur']}
  ],
});
const paramData = ref({});

const init = (options) => {
  formData.value = {
    id: options.id || '',
    folderId: options.folderId || '',
    name: '',
    type: options.type || "普通",
    compList: [],
    paramList: []
  };
  loadPage(options.id, options.showEdit || false);
};

const visualEdit = () => {
  if ((formData.value.layoutMode || '') === '') {
    ElMessage.error("请先选择布局模式！");
    return;
  }

  let visualJson = '';
  let paramList = [];
  if (formData.value.compList && formData.value.compList.length > 0) {
    visualJson = formData.value.compList[0].visualJson || '';
    paramList = formData.value.paramList || [];
  } else {
    formData.value.compList.push({
      name: '页面',
      type: '可视化',
      showComp: '1',
      buttonWrap: '0',
      visualJson: '',
      rowFlag: ++rowFlag.value
    });
  }
  visualOptions.value = { layoutMode: formData.value.layoutMode, paramList: paramList, json: visualJson };
  visualComp.value = markRaw(formData.value.layoutMode !== '大屏' ? VisualEditor : DashboardEditor);
  visualVisible.value = true;
};

const visualSave = (json, buttonList) => {
  const comp = formData.value.compList[0];
  comp.buttonList = buttonList || [];
  comp.visualJson = json || '';
  visualVisible.value = false;
};

const sortableParamInst = ref();
const sortParam = ref();
const sortParamList = () => {
  if (sortableParamInst.value) {
    sortableParamInst.value.destroy();
  }

  if (sortParam.value) {
    const el = sortParam.value;
    sortableParamInst.value = Sortable.create(el, {
      handle: '.param-item',
      onEnd: ({ newIndex, oldIndex}) => {
        const list = tool.deepClone(formData.value.paramList);
        const currRow = list.splice(oldIndex, 1)[0];
        list.splice(newIndex, 0, currRow);
        nextTick(() => {
          formData.value.paramList = list;
        });
      }
    });
  }
};

const closeParamList = () => {
  if (sortableParamInst.value) {
    sortableParamInst.value.destroy();
    sortableParamInst.value = null;
  }
};

const deleteSelectedParam = (param) => {
  ElMessageBox.confirm('删除后数据无法恢复，请确认是否删除？', '提示', {type: 'warning'}).then(() => {
    const index = formData.value.paramList.findIndex(item => item.id === param.id);
    formData.value.paramList.splice(index, 1);
  }).catch(() => {});
};

const editParam = (param) => {
  if (!param && (formData.value.paramList || []).length > 13) {
    ElMessage.error("最多只支持13个参数！");
    return;
  }

  if (param) {
    paramData.value = tool.deepClone(param);
    paramTitle.value = '编辑参数';
  } else {
    paramData.value = {
      id: 'temp_' + (++rowFlag.value)
    };
    paramTitle.value = '新增参数';
  }

  paramVisible.value = true;
};

const submitParamForm = () => {
  paramForm.value && paramForm.value.validate(valid => {
    if (valid) {
      if (!paramData.value.name.trim()) {
        ElMessage.error("参数名不能为空！");
        return;
      }

      const index = formData.value.paramList.findIndex(item => item.id === paramData.value.id);
      if (index >= 0) {
        formData.value.paramList[index] = paramData.value;
      } else {
        formData.value.paramList.push(paramData.value);
      }

      paramVisible.value = false;
    }
  });
};

const addComp = () => {
  compTitle.value = "新增组件";
  compData.value = {
    type: '表格',
    dataType: '数据模型',
    showComp: '1',
    autoHeight: '1',
    treeMappingType: '一对多',
    rowFlag: ++rowFlag.value
  };
  compVisible.value = true;
};

const editComp = (data) => {
  compTitle.value = "编辑组件";
  compData.value = tool.deepClone(data);
  compVisible.value = true;
};

const copyComp = (data) => {
  const newData = tool.deepClone(data);
  newData.id = '';
  newData.name = newData.name + "_复制";
  newData.rowFlag = ++rowFlag.value;
  formData.value.compList.push(newData);
  ElMessage.success("复制成功")
};

const deleteComp = (data) => {
  ElMessageBox.confirm('请确认是否删除【' + data.name + '】？', '提示', {type: 'warning'}).then(() => {
    const index = formData.value.compList
      .findIndex(item => data.id ? item.id === data.id : item.rowFlag === data.rowFlag);
    formData.value.compList.splice(index, 1);
  }).catch(() => {});
};

const submitCompForm = () => {
  compComp.value.validate(valid => {
    if (valid) {
      const data = compComp.value.getData();
      const index = formData.value.compList
        .findIndex(item => data.id ? item.id === data.id : item.rowFlag === data.rowFlag);
      if (index >= 0) {
        formData.value.compList[index] = data;
      } else {
        formData.value.compList.push(data);
      }

      compVisible.value = false;
    } else {
      ElMessage.error("数据录入不正确，请重新检查！");
    }
  });
};

const loadPage = (id, showEdit) => {
  if (id) {
    loading.showLoading();
    api.post('/system/page/queryBy', {id: id}).then(async res => {
      const data = res.data || {};
      data.compList = data.compList || [];
      data.paramList = data.paramList || [];
      for (let i=0; i<data.compList.length; i++) {
        const compRes = await api.post('/system/pageComp/queryBy', {id: data.compList[i].id});
        data.compList[i] = compRes.data || {};
      }
      formData.value = data;
      if (showEdit) {
        visualEdit();
      }
      loading.hideLoading();
    }).catch(() => loading.hideLoading());
  }
  clearValidate();
};

const submitData = () => {
  dataForm.value && dataForm.value.validate((valid) => {
    if (valid) {
      ElMessageBox.confirm("请确认是否提交？", "提示", { type: "info" }).then(() => {
        loading.showLoading();
        api.post('/system/page/save', formData.value).then(res => {
          ElMessage.success(res.message);
          emit('afterSubmit', res.data)
          loading.hideLoading();
        }).catch(() => loading.hideLoading());
      }).catch(() => {});
    }
  });
};

const getData = () => {
  return formData.value;
};

const validate = () => {
  return new Promise((resolve) => {
    dataForm.value.validate(valid => resolve(valid));
  });
};

const getRowKey = (data) => {
  return data.id || data.rowFlag;
};

const sortPageComp = () => {
  if (sortableInst.value) {
    sortableInst.value.destroy();
  }

  if (sortTable.value) {
    const el = sortTable.value.$el.querySelector(".el-table__body-wrapper tbody");
    sortableInst.value = Sortable.create(el, {
      handle: '.el-table__row',
      onEnd: ({ newIndex, oldIndex}) => {
        const list = tool.deepClone(formData.value.compList);
        const currRow = list.splice(oldIndex, 1)[0];
        list.splice(newIndex, 0, currRow);
        nextTick(() => {
          formData.value.compList = list;
        });
      }
    });
  }
};

const unSortPageComp = () => {
  if (sortableInst.value) {
    sortableInst.value.destroy();
  }
  sortableInst.value = null;
};

const clearValidate = () => {
  nextTick(() => {
    dataForm.value && dataForm.value.clearValidate();
  });
};

watch(() => props.options, (options) => {
  init(options || {});
});

onMounted(() => {
  init(props.options || {});
});

defineExpose({ submitData, clearValidate, getData, validate });
</script>

<style scoped lang="scss">
.param-box {
  display: contents;
  .param-item {
    padding: 0 15px;
    border: 1px solid #dcdfe6;
    border-radius: 5px;
    margin: 0 8px 0 0;
    height: 30px;
    display: flex;
    flex-direction: row;
    justify-content: center;
    align-items: center;
    :deep(.ac-icon) {
      margin-left: 8px;
      cursor: pointer;
    }
  }
  :deep(.el-button) {
    margin: 2px 8px 2px 0 ;
  }
}
.section-tips {
  font-size: 15px;
  font-weight: 900;
  display: inline-flex;
  align-items: center;
  height: 100%;
}
</style>